package cn.sangedon.review.analysis.stastics.specific;

import cn.sangedon.review.analysis.constant.StrategyEnum;
import cn.sangedon.review.analysis.service.StockStrategyResultService;
import cn.sangedon.review.common.constant.TypeConstant;
import cn.sangedon.review.common.domain.analysis.StockStrategy;
import cn.sangedon.review.common.domain.analysis.StockStrategyResult;
import cn.sangedon.review.common.domain.data.StockDayInfo;
import cn.sangedon.review.common.service.data.StockDayInfoService;
import cn.sangedon.review.common.service.data.TradingDateService;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

/**
 * 定期运行分析策略结果第二天行情
 */
@Slf4j
@Component
public class StrategyVerifyStastics extends AbstractScheduleStastics {
    @Autowired
    private StockStrategyResultService stockStrategyResultService;

    @DubboReference
    private StockDayInfoService stockDayInfoService;

    @DubboReference
    private TradingDateService tradingDateService;

    @Override
    public void runJob(List<StockStrategy> strategyList) {
        strategyList.stream().filter(e -> e.getStrategyName().equals(StrategyEnum.STRATEGY_VERIFY.getName())).findFirst().ifPresent(e -> {
            addSchedule(e);
        });
    }

    @Override
    public void stastic() {
        verifyTomorrow();

        //        verifyAfterTomorrow();
        //
        //        verifyThreeDaysFromNow();
    }

    /*private void verifyThreeDaysFromNow() {
        log.info("开始验证交易策略第二天行情");
        Long needVerifyNum = stockStrategyResultService.countNeedVerifyResult();
        if (needVerifyNum == null || needVerifyNum == 0) {
            log.info("无待验证交易策略结果");
            return;
        }

        verifyStragegyResult(stockStrategyResultService.getLatestResult());
        log.info("验证最近策略结果第二天行情成功");
    }

    private void verifyAfterTomorrow() {
        log.info("开始验证交易策略第三天行情");
        Long needVerifyNum = stockStrategyResultService.countNeedVerifyTomorrow();
        if (needVerifyNum == null || needVerifyNum == 0) {
            log.info("无待验证交易策略结果");
            return;
        }

        verifyStragegyResult(stockStrategyResultService.getLatestResult());
        log.info("验证最近策略结果第三天行情成功");
    }*/

    private void verifyTomorrow() {
        log.info("开始验证交易策略第二天行情");
        Long needVerifyNum = stockStrategyResultService.countNeedVerifyResult();
        if (needVerifyNum == null || needVerifyNum == 0) {
            log.info("无待验证交易策略结果");
            return;
        }

        verifyStragegyResult(stockStrategyResultService.getLatestResult());
        log.info("验证最近策略结果第二天行情成功");
    }

    /**
     * 验证某日的策略结果第二天行情
     *
     * @param results 某日的策略结果
     * @return
     */
    public void verifyStragegyResult(List<StockStrategyResult> results) {
        List<StockStrategyResult> toVerifyResult = results.stream().filter(e -> {
            return StringUtils.isEmpty(e.getNextDayChangeRate()) && StringUtils.isEmpty(e.getNextDayBottomChangeRate()) &&
                   StringUtils.isEmpty(e.getNextDayPeakChangeRate());
        }).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(toVerifyResult)) {
            log.info("无待验证交易策略结果");
            return;
        }

        log.info("开始验证:{}策略结果", results.get(0).getTradingDate());
        String nextTradeDate = tradingDateService.postTradingDay(toVerifyResult.get(0).getTradingDate(), 1).current().getTradingDate();
        List<StockDayInfo> stockDayInfos = stockDayInfoService.getStockDayInfos(nextTradeDate, TypeConstant.EQ);
        if (CollectionUtils.isEmpty(stockDayInfos)) {
            log.info("最近策略结果第二天行情数据还未更新,请先更新每日行情数据在重试");
            return;
        }

        Map<String, StockDayInfo> quotationMap = stockDayInfos.parallelStream()
                                                              .collect(Collectors.toMap(StockDayInfo::getCode, Function.identity()));

        for (StockStrategyResult strategyResult : toVerifyResult) {
            StockDayInfo stockDayInfo = quotationMap.get(strategyResult.getStockCode());
            strategyResult.setNextDayBottomChangeRate(calulateChangeRate(stockDayInfo.getBottomPrice(), stockDayInfo.getLastClosePrice()));
            strategyResult.setNextDayChangeRate(stockDayInfo.getChangeRate().toString());
            strategyResult.setNextDayPeakChangeRate(calulateChangeRate(stockDayInfo.getPeakPrice(), stockDayInfo.getLastClosePrice()));
            strategyResult.setRise(stockDayInfo.getChangeRate().signum() >= 0 ? 1 : 0);
        }
        stockStrategyResultService.saveOrUpdateBatch(toVerifyResult);
    }

    private String calulateChangeRate(BigDecimal bottomPrice, BigDecimal openingPrice) {
        double value = bottomPrice.subtract(openingPrice).divide(openingPrice, 4, RoundingMode.HALF_UP).doubleValue() * 100;
        return String.valueOf(value);
    }
}
